#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#include <wx/wx.h>
#include <wx/socket.h>
#include <wx/cmdline.h>

#include <algorithm>
#include <queue>
#include <set>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

//---------------------------------------------------------------------------
class MyApp : public wxApp
{
	void OnInitCmdLine(wxCmdLineParser &parser);
	bool OnCmdLineParsed(wxCmdLineParser &parser);
	int OnExit();
	void ExitMainLoop();
	int OnRun();
private:
	wxSocketServer *SocketServer;
};
//---------------------------------------------------------------------------

IMPLEMENT_APP(MyApp);
//---------------------------------------------------------------------------
void ShowCmdLine(const wxCmdLineParser& parser)
{
	wxString s = _T("Command line parsed successfully:\n");
	size_t count = parser.GetParamCount();
	for (size_t param = 0; param < count; param++)
		s << parser.GetParam(param) << ' ';

	long lVal;
	if (parser.Found(_T("p"), &lVal))
		s << _T("Listen Port:\t") << lVal << '\n';

	if (parser.Found(_T("v")))
		s << _T("Server Version: 1.0") << '\n';

	wxPrintf(s.c_str());
        fflush(stdout);
}
//---------------------------------------------------------------------------
wxString path;
void MyApp::OnInitCmdLine(wxCmdLineParser &parser)
{
	path = wxPathOnly(argv[0]);
	const wxCmdLineEntryDesc cmdLineDesc[] =
	{
		{ wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show this help message"),
			wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },

		{ wxCMD_LINE_OPTION, _T("p"), _T("Port"),  _T("listen port"),
			wxCMD_LINE_VAL_NUMBER },

		{ wxCMD_LINE_SWITCH, _T("v"), _T("version"),  _T("Server Version"),
			wxCMD_LINE_VAL_NONE },

		{ wxCMD_LINE_NONE }
	};
	parser.SetDesc(cmdLineDesc);
}
//---------------------------------------------------------------------------
bool MyApp::OnCmdLineParsed(wxCmdLineParser &parser)
{
	int port = 40003;
	long val;
	if (parser.Found(_T("p"), &val))
		port = val;

	ShowCmdLine(parser);

	// Create the address - defaults to localhost:0 initially
	wxIPV4address addr;
	addr.Service(port);
	// Create the socket
	SocketServer = new wxSocketServer(addr);
	if (SocketServer->Ok())
	{
		wxPrintf(_T("SocketServer->Ok()\n"));
		fflush(stdout);
	}
}
//---------------------------------------------------------------------------
int MyApp::OnExit()
{
	wxPrintf(_T("Server stopped\n"));
	SocketServer->Destroy();
	return wxApp::OnExit();
}
//---------------------------------------------------------------------------
void MyApp::ExitMainLoop()
{
	wxPrintf(_T("Exit main loop\n"));
	fflush(stdout);
}
//---------------------------------------------------------------------------
queue<wxSocketBase *> socket_pending;
void on_connect(wxSocketBase *sock)
{
	socket_pending.push(sock);
	wxPrintf(_T("pending, %d\n"), socket_pending.size());
	wxPrintf(_T("accept\n"));
}
void on_disconnect(wxSocketBase *sock)
{
	sock->Destroy();
	wxPrintf(_T("disconnect\n"));
}
void on_read(wxSocketBase *sock, char *buf, int len)
{
	wxPrintf(_("Read.\n"));
	if (len > 0) {
		vector<char> v;
		copy(buf, buf + len, back_inserter(v));
		bool succ = !sock->Write(&v[0], v.size()).Error();
		if (succ) {
		}
	}
}
int MyApp::OnRun()
{
	wxPrintf(_T("OnRun\n"));
	
	while(1) {
		wxSocketBase *sock = SocketServer->Accept(false);
		if (sock) {
	  		sock->SetFlags(wxSOCKET_NOWAIT);// or blocking by read/write
	  		on_connect(sock);
	  	}
		SocketServer->SetTimeout(60); // 1 min

		while(socket_pending.empty() == false) {
			wxSocketBase *sock = socket_pending.front();
			socket_pending.pop();
			if (sock->IsConnected()) {
				char buffer[1024];
				bool succ = !sock->Read(buffer, 1024).Error();
				if (succ) {
					int len = sock->LastCount();
					on_read(sock, buffer, len);
				} 
				socket_pending.push(sock);
			} else {
				on_disconnect(sock);
			}
		}
		fflush(stdout);
		wxMilliSleep(1);
	}
	return 0;
}
//---------------------------------------------------------------------------

